package com.lyf.scm.plan.domain.service.impl;

import com.lyf.scm.plan.domain.service.RedisService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;

import javax.annotation.Nullable;
import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * redis服务器测试
 *
 * @author wangchlei
 * @date 2020/09/20
 */
@Service
public final class RedisServiceImpl implements RedisService {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 获取所有键值对
     *
     * @param
     * @return {@link  List<Map<Object, Object>>}
     **/
    @Override
    public List<Map<Object, Object>> getAllRedisVal1() {

        List<Map<Object, Object>> list = new ArrayList<>();
        //key("*") 获取所有键
        Set<String> keys = redisTemplate.keys("*");
        for (String key : keys) {
            HashMap<Object, Object> map = new HashMap<>();
            //String类型的键值获取
            if ("string".equals(redisTemplate.type(key).code())) {
                Object value = redisTemplate.opsForValue().get(key);

                map.put("key", key);
                map.put("value", value);
                list.add(map);
            }
            //zset类型的键值获取
            if ("zset".equals(redisTemplate.type(key).code())) {
                Object value = redisTemplate.opsForZSet().range(key, 0, -1);
                map.put("key", key);
                map.put("value", value);
                list.add(map);
            }
            //set类型的键值获取
            if ("set".equals(redisTemplate.type(key).code())) {
                Object value = redisTemplate.opsForZSet().range(key, 0, -1);
                map.put("key", key);
                map.put("value", value);
                list.add(map);
            }
            //list类型的键值获取
            if ("list".equals(redisTemplate.type(key).code())) {
                Object value = redisTemplate.opsForZSet().range(key, 0, -1);
                map.put("key", key);
                map.put("value", value);
                list.add(map);
            }
            //hash类型的键值获取
            if ("hash".equals(redisTemplate.type(key).code())) {
                Object value = redisTemplate.opsForZSet().range(key, 0, -1);
                map.put("key", key);
                map.put("value", value);
                list.add(map);
            }
        }

        return list;
    }

    /**
     * 分页获取所有键值对
     *
     * @param pageSize
     * @param pageNumber
     * @return {@link List<Map<Object,Object>>}
     **/
    @Override
    public List<Map<Object, Object>> getAllRedisVal2(Integer pageSize, Integer pageNumber) {
        List<Map<Object, Object>> list = new ArrayList<>();
        int startIndex = pageSize * (pageNumber - 1) + 1;
        //使用scan的方法
        Map<Object, Object> result = (Map<Object, Object>) redisTemplate.execute(new RedisCallback() {
            @Nullable
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                Cursor<byte[]> results = redisConnection.scan(new ScanOptions.ScanOptionsBuilder().match("*").build());
                List<String> keys = new LinkedList<>();
                Map<Object, Object> map = new HashMap<>();
                try {
                    int index = 0;
                    while (results.hasNext()) {

                        if (startIndex <= index && index < pageSize + startIndex) {
                            keys.add(new String(results.next(), "UTF-8"));
                        } else {
                            results.next();
                        }
                        index++;
                    }
                    map.put("count", index);
                    map.put("keys", keys);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                return map;
            }
        });
        List<String> keys = (List<String>) result.get("keys");
        for (String key : keys) {
            HashMap<Object, Object> map = new HashMap<>();
            if ("string".equals(redisTemplate.type(key).code())) {
                Object value = redisTemplate.opsForValue().get(key);

                map.put("key", key);
                map.put("value", value);
                list.add(map);
            } else if ("zset".equals(redisTemplate.type(key).code())) {
                Object value = redisTemplate.opsForZSet().range(key, 0, -1);
                map.put("key", key);
                map.put("value", value);
                list.add(map);
            } else if ("set".equals(redisTemplate.type(key).code())) {
                Object value = redisTemplate.opsForSet().members(key);
                map.put("key", key);
                map.put("value", value);
                list.add(map);
            } else if ("list".equals(redisTemplate.type(key).code())) {
                Object value = redisTemplate.opsForList().range(key, 0, -1);
                map.put("key", key);
                map.put("value", value);
                list.add(map);
            } else if ("hash".equals(redisTemplate.type(key).code())) {
                Object value = redisTemplate.opsForHash().entries(key);
                map.put("key", key);
                map.put("value", value);
                list.add(map);
            } else if ("none".equals(redisTemplate.type(key).code())) {
                Object value = redisTemplate.opsForHash().entries(key);
                map.put("key", key);
                map.put("value", value);
                list.add(map);
            }
        }

        Map<Object, Object> map = new HashMap<>();
        map.put("count", result.get("count"));
        list.add(map);
        return list;
    }

    /**
     * 根据key读取缓存
     *
     * @param key
     * @return {@link Object}
     **/
    @Override
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 设置 key--value 键值对
     *
     * @param key
     * @param value
     * @return {@link boolean}
     **/
    @Override
    public boolean set(String key, Object value) {
        boolean result = false;
        try {
            redisTemplate.opsForValue().set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 设置 key--value 键值对（含有失效时长,秒为单位）
     *
     * @param key
     * @param value
     * @param expireTime
     * @return {@link boolean}
     **/
    @Override
    public boolean set(String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            redisTemplate.opsForValue().set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 批量删除 key--value 键值对
     *
     * @param keys
     * @return void
     **/
    @Override
    public boolean remove(String... keys) {
        boolean result = false;
        try {
            for (String key : keys) {
                remove(key);
            }
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 删除 key--value 键值对
     *
     * @param key
     * @return void
     **/
    @Override
    public void remove(String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }

    /**
     * 判断是否存在对应key
     *
     * @param key
     * @return {@link boolean}
     **/
    @Override
    public boolean exists(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 获取key的失效时长（秒）
     *
     * @param key
     * @return {@link Object}
     **/
    @Override
    public Long getExpireTime(String key) {
        return redisTemplate.opsForValue().getOperations().getExpire(key);
    }

    @Override
    public void batchRemove(String key) {
        Set<String> keys = redisTemplate.keys(key + "*");
        if(!CollectionUtils.isEmpty(keys)){
            redisTemplate.delete(keys);
        }
    }

    @Override
    public void removePattern(String pattern) {

    }

    @Override
    public void hmSet(String key, Object hashKey, Object value) {

    }

    @Override
    public Object hmGet(String key, Object hashKey) {
        return null;
    }

    @Override
    public void lPush(String k, Object v) {
        ListOperations<String, Object> list = redisTemplate.opsForList();
        list.rightPush(k, v);
    }

    @Override
    public List<Object> lRange(String k, long l, long l1) {
        ListOperations<String, Object> list = redisTemplate.opsForList();
        return list.range(k, l, l1);
    }

    @Override
    public void setArray(String key, Object value) {

    }

    @Override
    public Set<Object> getArray(String key) {
        return null;
    }

    @Override
    public void zAdd(String key, Object value, double scoure) {

    }

    @Override
    public Set<Object> rangeByScore(String key, double scoure, double scoure1) {
        return null;
    }
}
